package com.jacobson.core.widget.security.realm

import com.jacobson.core.widget.logger.LoggerFactory
import com.jacobson.core.widget.security.authc.AuthenticationInfo
import com.jacobson.core.widget.security.authc.AuthenticationToken
import com.jacobson.core.widget.security.authc.credential.CredentialsMatcher
import com.jacobson.core.widget.security.authc.credential.SimpleCredentialsMatcher
import com.jacobson.core.widget.security.exception.IncorrectCredentialsException

/**
 * ================================================
 *
 *  @author Wucz on 2018/8/7 16:31
 * ================================================
 */
abstract class AuthenticatingRealm(
        var credentialsMatcher: CredentialsMatcher = SimpleCredentialsMatcher()
) : Realm {
    private val logger = LoggerFactory.getLogger()

    override fun supports(token: AuthenticationToken): Boolean = true

    override fun getAuthenticationInfo(token: AuthenticationToken): AuthenticationInfo? {
        val info: AuthenticationInfo? = getCachedAuthenticationInfo(token)?.let {
            logger.d("Using cached authentication info [{}] to perform credentials matching.", it)
            it
        } ?: run {
            this.doGetAuthenticationInfo(token)?.apply {
                logger.d("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", this)
                cacheAuthenticationInfoIfPossible(token, this)
            }
        }

        info?.let { assertCredentialsMatch(token, info) }
                ?: logger.d("No AuthenticationInfo found for submitted AuthenticationToken [{}].  Returning null.", token)
        return info
    }

    /**
     * 匹配证书信息
     */
    private fun assertCredentialsMatch(token: AuthenticationToken, info: AuthenticationInfo) {
        credentialsMatcher.takeIf { it.doCredentialsMatch(token, info) }?.let {
            val msg = "Submitted credentials for token [$token] did not match the expected credentials."
            throw IncorrectCredentialsException(msg)
        }
    }

    /**
     * TODO
     * 设置缓存-未支持
     */
    private fun cacheAuthenticationInfoIfPossible(token: AuthenticationToken, info: AuthenticationInfo) {
    }

    /**
     * TODO
     * 缓存策略-未支持
     */
    private fun getCachedAuthenticationInfo(token: AuthenticationToken): AuthenticationInfo? = null

    protected abstract fun doGetAuthenticationInfo(token: AuthenticationToken): AuthenticationInfo?
}